RemixでCloudflare R2にアップロードしてみる
はじめに
Cloudflare R2はAWS S3互換オブジェクトストレージです
このブログはR2について詳しい詳細は割愛します。エグレス料金が無料なのが魅力的です。
Cloudflare R2にRemixからデプロイする
R2を有効化します。
クレジットカード登録すれば有効化できます。無料枠もあります。
wrangler.tomlを作成する
local実行時のリソースや構成管理のためにwrangler.tomlを作っておきます。
$ bunx wrangler generate
Cloudflare R2のバケットをつくる
$ bunx wrangler r2 bucket create [BUCKET_NAME]
wrangler.tomlにR2をリソースを追加
name = "[PROJECT_NAME]" compatibility_date = "2023-09-22" [[r2_buckets]] binding = 'R2' bucket_name = '[BUCKET_NAME]'
RemixからR2バケットにアクセスする
最近のReactのフレームワークは単にSPAとして動くわけではなく、サーバー機能を持っていることが多くなっています。 シンプルにbuildにして、CDNとかで配信して終わりじゃなくなっています。
今回のRemixの用途も同じで、サーバーの機能を思っています。普通はサーバー部分はNodeやGOやPHPやRustなどで書くことが多いですが、Remixはサーバー部分もReactで書きます。なのでサーバーとクライアントで動く境界がわかりにくく、Nodeにしかない機能はクライアントではつかえず、ブラウザにしかない機能はサーバーではつかえません。どっちで動くコードなのか意識する必要があります。
今回のR2 Bucketも同じサーバーで取得できる機能となっています。
R2にアップロードしてみます。
import { type ActionFunctionArgs, json, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData, } from "@remix-run/cloudflare"; type AppEnv = { R2: R2Bucket; }; export async function action({request, context}: ActionFunctionArgs) { const env = context.env as AppEnv const uploadHandler = unstable_createMemoryUploadHandler({ maxPartSize: 1024 * 1024 * 10, }); const form = await unstable_parseMultipartFormData(request, uploadHandler); const file = form.get("file") as Blob; const response = await env.R2.put("file", await file.arrayBuffer(), { httpMetadata: { contentType: file.type, } }) return json({object: response}) } export default function Index() { return ( <div> <div> <form method={"POST"} encType="multipart/form-data"> <input type="file" name={"file"} /> <button type={"submit"}>送信</button> </form> </div> <div> <img src="/images/file" alt="" /> </div> </div> ); }
R2の画像を表示
R2のKeyをパスパラメータで取得するようにします。
import type { LoaderFunction } from "@remix-run/cloudflare"; import { json } from "@remix-run/cloudflare"; type AppEnv = { R2: R2Bucket; }; export const loader: LoaderFunction = async ({ params, context }) => { const key = params.key; if (key == null) { return json({ message: "Object not found" }, { status: 404 }); } const { R2 } = context.env as AppEnv; const object = await R2.get(key); if (object == null) { return json({ message: "Object not found" }, { status: 404 }); } const headers: HeadersInit = new Headers(); object.writeHttpMetadata(headers); headers.set("etag", object.etag); return new Response(object.body, { headers }); };
Cloudflare Pagesの設定からR2を使えるように設定する
Cloudflare PagesのSetttingsにfunctionsの設定に環境設定ができる項目から、R2をbindingします。
デプロイする
$ bun run build $ bun run pages:deploy
まとめ
Cloudflare R2にファイルをアップロードできるようになりました。R2のセットアップ済みのオブジェクトがもらえるので簡単に使えて便利です。 wrangler.tomlをかけばローカル時でも動いて、こんな簡単で良いのか不安になりますが、いい感じです。